package org.darkforest.common.mail;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.darkforest.common.logger.Logger;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.util.Assert;

import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * MailSender
 * Created by Justin on 15/3/14.
 */
public class MailSender {

    /**
     * 邮件发送对象.
     */
    private JavaMailSender mailSender;
    /**
     * 系统发件人.
     */
    private String systemSender;
    /**
     * 调试模式开关.
     */
    private boolean debug = false;
    /**
     * 调试模式下的收件人.
     */
    private String debugReceiver;
    /**
     * 一次发送最多可以接受的收件人数量，默认为50.
     */
    private int maxReceiversOnce = 50;
    /**
     * 邮件编码，默认为UTF-8.
     */
    private String encode = "UTF-8";

    /**
     * 使用系统发件人发送邮件.
     *
     * @param subject   邮件标题
     * @param content   邮件正文
     * @param sender    发件人
     * @param receivers 收件人
     */
    public void sendAsynchronousMail(final String subject, final String content, final String sender,
                                     final String... receivers) {
        new Thread() {
            @Override
            public void run() {
                send(subject, content, sender, receivers);
            }
        }.start();
    }

    /**
     * 使用系统发件人发送邮件.
     *
     * @param subject   邮件标题
     * @param content   邮件正文
     * @param receivers 收件人
     */
    public void send(String subject, String content, String... receivers) {
        send(subject, content, null, receivers);
    }

    /**
     * 发送邮件.
     * <p>
     * 如果收件人数量大于一次最大可发送数量，则自动拆分为多组发送.
     * </p>
     *
     * @param subject   邮件标题
     * @param content   邮件正文
     * @param sender    发件人
     * @param receivers 收件人
     */
    public void send(String subject, String content, String sender, String[] receivers) {
        this.send(subject, content, receivers, sender, null, null, null, null, false);
    }

    /**
     * 发送邮件.
     * <p>
     * 如果收件人数量大于一次最大可发送数量，则自动拆分为多组发送.
     * </p>
     *
     * @param subject            邮件标题
     * @param content            邮件正文
     * @param receivers          收件人
     * @param sender             发件人
     * @param cc                 抄送人
     * @param bcc                暗送人
     * @param attachmentFilename 附件名称
     * @param attach             附件文件
     * @param attachAsMIME       附件是否使用MIME方式发送（在邮件体中使用的对象、图片，使用非MIME方式发送，邮件的附件需要使用MIME方式发送）
     */
    public void send(String subject, String content, String[] receivers, String sender, String[] cc, String[] bcc,
                     String attachmentFilename[], File attach[], boolean attachAsMIME) {

        List<String> group = new ArrayList<String>(maxReceiversOnce);
        for (int i = 0; i < receivers.length; i++) {
            if (i % maxReceiversOnce == 0 && !group.isEmpty()) {
                sendOnce(subject, content, group.toArray(new String[group.size()]), sender, cc, bcc,
                        attachmentFilename, attach, attachAsMIME);
                group.clear();
            }
            group.add(receivers[i]);
        }

        if (!group.isEmpty()) {
            sendOnce(subject, content, group.toArray(new String[group.size()]), sender, cc, bcc, attachmentFilename,
                    attach, attachAsMIME);
        }
    }

    /**
     * 发送一次邮件.
     *
     * @param subject            邮件标题
     * @param content            邮件正文
     * @param receivers          收件人
     * @param sender             发件人
     * @param cc                 抄送人
     * @param bcc                暗送人
     * @param attachmentFilename 附件名称
     * @param attach             附件文件
     */
    private void sendOnce(String subject, String content, String[] receivers, String sender, String[] cc,
                          String[] bcc, String[] attachmentFilename, File[] attach, boolean attachAsMIME) {

        Assert.hasText(subject);
        Assert.notNull(content);
        Assert.notEmpty(receivers);

        // 检测在调试模式下是否允许发送邮件
        if (debug && StringUtils.isBlank(debugReceiver)) {
            Logger.warn(MailSender.class,
                    "Mail [ SUBJECT: {}, RECEIVER(S): {} ] did not send because [debugReceiver] not set.",
                    subject, Arrays.toString(receivers));
            return;
        }

        // 创建MIME消息准备发送邮件
        MimeMessage message = mailSender.createMimeMessage();

        try {

            MimeMessageHelper helper = new MimeMessageHelper(message, true, encode);

            // 调试模式
            if (debug) {
                content = content + "<br /> Receivers：" + Arrays.toString(receivers) + "<br /> CC: " + Arrays
                        .toString(cc) + "<br /> BCC: " + Arrays.toString(bcc);
                subject = "Debug mail：" + subject;
                helper.setTo(debugReceiver);
            }
            // 非调试模式
            else {
                if (!ArrayUtils.isEmpty(bcc)) {
                    helper.setBcc(bcc);
                }
                if (!ArrayUtils.isEmpty(cc)) {
                    helper.setCc(cc);
                }
                helper.setTo(receivers);
            }

            helper.setFrom(StringUtils.isBlank(sender) ? systemSender : sender);
            helper.setSubject(subject);
            helper.setText(content, true);

            if (attachmentFilename != null && attachmentFilename.length > 0) {
                for (int i = 0; i < attachmentFilename.length; i++) {
                    // 设置附件
                    if (attachmentFilename[i] != null && attach[i] != null && attach[i].exists()) {
                        if (attachAsMIME) {
                            helper.addAttachment(attachmentFilename[i], attach[i]);
                        } else {
                            FileSystemResource img = new FileSystemResource(attach[i]);
                            helper.addInline(attachmentFilename[i], img);
                        }
                    }
                }
            }
        } catch (Exception ex) {
            Logger.error(MailSender.class, "Mail send fail.", ex);
            //邮件发送出错不抛出
            //throw new RuntimeException(ex);
        }

        Logger.info(MailSender.class, "Sending mail [ SUBJECT: {} ] to [ RECEIVER(S): {} ]...", subject, Arrays.toString
                (receivers));
        mailSender.send(message);
    }

    @Required
    public void setMailSender(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }

    @Required
    public void setSystemSender(String systemSender) {
        this.systemSender = systemSender;
    }

    public void setEncode(String encode) {
        this.encode = encode;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    public void setDebugReceiver(String debugReceiver) {
        this.debugReceiver = debugReceiver;
    }

    public void setMaxReceiversOnce(int maxReceiversOnce) {
        this.maxReceiversOnce = maxReceiversOnce;
    }

}
